package net.oschina.allchat.server.framework.im;

import java.util.HashMap;
import java.util.Map;

import net.oschina.allchat.protocol.im.stanza.Message;
import net.oschina.allchat.server.framework.core.annotations.Component;
import net.oschina.allchat.server.framework.core.commons.osgi.IBundleContextAware;
import net.oschina.allchat.server.framework.core.commons.osgi.IContributionTracker;
import net.oschina.allchat.server.framework.core.commons.osgi.OsgiUtils;
import net.oschina.allchat.server.framework.core.config.IApplicationConfiguration;
import net.oschina.allchat.server.framework.core.config.IApplicationConfigurationAware;
import net.oschina.allchat.server.framework.core.connection.IConnectionContext;
import net.oschina.allchat.server.framework.core.repository.IDependencyManager;
import net.oschina.allchat.server.framework.core.repository.IDependencyManagerAware;
import net.oschina.allchat.server.framework.core.repository.IInitializable;
import net.oschina.allchat.server.framework.pipe.processing.IMessageProcessor;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

@Component("default.message.processor")
public class DefaultMessageProcessor implements IMessageProcessor, IBundleContextAware,
			IContributionTracker, IInitializable, IDependencyManagerAware,
				IApplicationConfigurationAware {
	private static final String KEY_ALL_CHAT_MESSAGE_PROCESSOR = "AllChat-Message-Processor";
	
	private BundleContext bundleContext;
	private Map<Bundle, IMessageProcessor> messageProcessors;
	
	private IDependencyManager dependencyManager;
	private IApplicationConfiguration appConfiguration;
	
	public DefaultMessageProcessor() {
		messageProcessors = new HashMap<Bundle, IMessageProcessor>();
	}
	
	@Override
	public void init() {
		OsgiUtils.trackContribution(bundleContext, KEY_ALL_CHAT_MESSAGE_PROCESSOR, this);
	}

	@Override
	public boolean process(IConnectionContext context, Message message) {
		for (IMessageProcessor messageProcessor : messageProcessors.values()) {
			if (messageProcessor.process(context, message))
				return true;
		}
		
		return false;
	}

	@Override
	public void setBundleContext(BundleContext bundleContext) {
		this.bundleContext = bundleContext;
	}

	@Override
	public void found(Bundle bundle, String contribution) throws Exception {
		Class<?> clazz = bundle.loadClass(contribution);
		if (!IMessageProcessor.class.isAssignableFrom(clazz)) {
			throw new IllegalArgumentException(String.format("%s must implement %",
				contribution, IMessageProcessor.class));
		}
		
		IMessageProcessor messageProcessor = (IMessageProcessor)clazz.newInstance();
		dependencyManager.inject(messageProcessor);
		
		if (messageProcessor instanceof IApplicationConfigurationAware) {
			((IApplicationConfigurationAware)messageProcessor).setApplicationConfiguration(appConfiguration);
		}
		
		messageProcessors.put(bundle, messageProcessor);
	}

	@Override
	public void lost(Bundle bundle, String contribution) throws Exception {
		messageProcessors.remove(bundle);
	}

	@Override
	public void setDependencyManager(IDependencyManager dependencyManager) {
		this.dependencyManager = dependencyManager;
	}

	@Override
	public void setApplicationConfiguration(IApplicationConfiguration appConfiguration) {
		this.appConfiguration = appConfiguration;
	}

}
